package com.usdt.system.service.impl.cp;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.usdt.common.config.OssWrapper;
import com.usdt.common.core.domain.OssPolicyResult;
import com.usdt.common.core.domain.entity.SysFile;
import com.usdt.common.enums.FileAccessLevel;
import com.usdt.common.exception.ServiceException;
import com.usdt.common.utils.bean.BeanUtil;
import com.usdt.system.cp.utils.FileDownloader;
import com.usdt.system.domain.req.DownloadFileVo;
import com.usdt.system.domain.resp.OssFileVo;
import com.usdt.system.mapper.SysFileMapper;
import com.usdt.system.service.cp.IOssService;

import lombok.extern.slf4j.Slf4j;

/**
 * oss上传管理Service实现类 Created by macro on 2018/5/17.
 */
@Service
@Slf4j
public class OssServiceImpl implements IOssService {

	@Autowired
	private OssWrapper ossWrapper;
	@Autowired
	private SysFileMapper fileMapper;

	/**
	 * 签名生成
	 */
	@Override
	public OssPolicyResult policy() {
		return ossWrapper.policy();
	}

	@Override
	public SysFile uploadCallback(SysFile fileInfo) {
		if (fileInfo == null) {
			return null;
		}
		if (fileMapper.get(fileInfo.getFileKey()) != null) {
			log.info("上传的文件key({})已经存在,旧文件将被覆盖", fileInfo.getFileKey());
			fileMapper.del(fileInfo.getFileKey());
		}

		if (fileInfo.getAccessLevel() == null) {
			fileInfo.setAccessLevel(FileAccessLevel.Default);
		} else {
			// 安全起见 这里不应该允许 accessLevel = PublicReadWrite
			ossWrapper.setFileAccessLevel(fileInfo.getFileKey(), fileInfo.getAccessLevel());
		}

		if (StringUtils.isNoneEmpty(fileInfo.getFileName())) {
			// 也许需要设置元信息(使得文件在下载时显示的文件名) 但是更好选择并不是在这里 而是前端上传插件处 指定对象元信息(meta)
			// ossWrapper.writeFileNameToObjectMeta(fileInfo.getFileKey(),
			// fileInfo.getFileName());
		}

		fileInfo.setFileEndpoint(ossWrapper.getEndpoint());
		fileInfo.setFileBucket(ossWrapper.getBucket());
		fileInfo.setCreateDate(new Date());
		fileInfo.setIsDeleted(false);
		int r = fileMapper.insert(fileInfo);
		log.info("保存上传记录结果:" + r);
		return fileInfo;
	}

	@Override
	public String getDownloadUrl(String fileKey) {
		SysFile file = fileMapper.get(fileKey);
		return ossWrapper.getDownloadUrl(fileKey,file != null ? file.getFileName() : null).toString();
	}

	@Override
	public String getDownloadUrl(String fileKey, String fileName) {
		if (StringUtils.isEmpty(fileName)) {
			SysFile file = fileMapper.get(fileKey);
			if (file != null) {
				fileName = file.getFileName();
			}
		}
		return ossWrapper.getDownloadUrl(fileKey, fileName).toString();
	}

	@Override
	public String getDownloadUrl(String key, String fileName, Integer isPreview) {
		if (StringUtils.isEmpty(fileName)) {
			SysFile file = fileMapper.get(key);
			if (file != null) {
				fileName = file.getFileName();
			}
		}
		return ossWrapper.getDownloadUrl(key, fileName, isPreview).toString();
	}

	/**
	 * 查询文件信息并附带 时效性的url
	 *
	 * @param keys
	 * @return
	 */
	public List<OssFileVo> queryFilesWithUrl(List<String> keys) {
		return baseQueryFilesWithUrl(VoAdaptor.keysToRequests(keys), false);
	}

	/**
	 * 批量获得 文件信息（附带下载链接）
	 *
	 * @param keys
	 * @return
	 */
	public List<OssFileVo> getDownloadUrls(List<DownloadFileVo> keys) {
		return baseQueryFilesWithUrl(keys, false);
	}

	/**
	 * 【最终方法】批量查询 文件信息并附带url
	 *
	 * @return
	 * @Param isPermanent 是否创建永久的url
	 */
	public List<OssFileVo> baseQueryFilesWithUrl(List<DownloadFileVo> requests, boolean isPermanent) {

		if (CollectionUtils.isEmpty(requests)) {
			throw new ServiceException("DownloadFileVo List 不能为空");
		}
		List<OssFileVo> out = new LinkedList<>();
		for (DownloadFileVo req : requests) {

			if (req == null || req.getFileKey() == null) {
				log.warn("传入了参数不合法:{}", requests);
				continue;
			}

			// 查文件信息
			OssFileVo fileVo = BeanUtil.toBean(fileMapper.get(req.getFileKey()), OssFileVo.class);

			// 在工具中台没有找到对应文件信息时 这种情况大多是因为文件在彩招上传的（也可能传入的key是错的） 中台是拿不到文件信息的 只能返回url
			if (fileVo == null) {
				fileVo = new OssFileVo();
				fileVo.setFileKey(req.getFileKey());
				fileVo.setFileName(req.getFileName());
			}
			// 浏览器下载弹框显示名 如果req指定了 优先用指定的文件名 未指定用数据库保存的文件名
			String browserDisplayName;
			if (StringUtils.isNotBlank(req.getFileName())) {
				browserDisplayName = req.getFileName();
			} else {
				browserDisplayName = fileVo.getFileName();
			}

			// 获得下载链接
			try {
				fileVo.setUrl(
						isPermanent ? new URL(ossWrapper.getPermanentDownloadUrl(req.getFileKey()))
								: ossWrapper.getDownloadUrl(req.getFileKey(), browserDisplayName));
			} catch (MalformedURLException e) {
				// URL实例化失败异常无法处理 为了防止check异常恶心人 这里换成另一个异常抛出
				throw new IllegalStateException(e);
			}

			out.add(fileVo);
		}

		return out;
	}

	/**
	 * 数据转换
	 */
	private static class VoAdaptor {

		public static List<DownloadFileVo> keysToRequests(List<String> keys) {
			if (CollectionUtils.isEmpty(keys)) {
				return null;
			}
			return keys.stream().map(k -> new DownloadFileVo().setFileKey(k)).collect(Collectors.toList());
		}

		public static List<DownloadFileVo> keysNameToRequests(List<String> keys, List<String> names) {
			if (CollectionUtils.isEmpty(keys)) {
				return null;
			}
			List<DownloadFileVo> requests = new LinkedList<>();
			for (int i = 0; i < keys.size(); i++) {
				String fileName = null;
				if (CollectionUtils.isNotEmpty(names) && names.size() > i)
					fileName = names.get(i);
				requests.add(new DownloadFileVo().setFileKey(keys.get(i)).setFileName(fileName));
			}
			return requests;
		}

	}

	@Override
	public String download(String fileKey,String downloadPath) {
		SysFile file = fileMapper.get(fileKey);
		if (file == null) {
			throw new ServiceException("文件不存在");
		}
		File path = new File(downloadPath);
		if (!path.exists()) {
			path.mkdir();
		}
		String downloadUrl = getDownloadUrl(fileKey);
		downloadPath += File.separator + file.getFileName();
		try {
			FileDownloader.downloadFile(downloadUrl, downloadPath);
		} catch (IOException e) {
			e.printStackTrace();
			throw new ServiceException("文件下载失败");
		}
		return downloadPath;
	}

}
